import { useState, useRef, useEffect } from "react";
import Log from "./log";
import { WebsocketPropsType } from "./type";
import urlCheck from "./urlCheck";
import useInterval from "./useInterval";

const stateArr = [
	{ key: 0, value: "正在链接中" },
	{ key: 1, value: "已经链接并且可以通讯" },
	{ key: 2, value: "连接正在关闭" },
	{ key: 3, value: "连接已关闭或者没有链接成功" },
];

const useWebsocket = (props: WebsocketPropsType) => {
	const {
		socketUrl,
		isLog = false,
		isReload = true,
		reloadStep = 5,
		isJson = true,
		clearTime = 5000,
	} = props;
	const log = Log(isLog);
	const ws = useRef<WebSocket | null>(null);
	const [url, setUrl] = useState(socketUrl);
	const [wsData, setMessage] = useState("");
	const [step, setStep] = useState<number>(1);
	const [readyState, setReadyState] = useState({
		key: 0,
		value: "正在链接中",
		message: {},
	});
	// 定时器，再一定时间后重启
	const [timer, setTimer] = useState<NodeJS.Timeout | null>(null);
	const [close, setClose] = useState(false);

	const creatWebSocket = (url: string) => {
		try {
			ws.current = new WebSocket(url);
			ws.current.onopen = (e) => {
				log.showLog("已打开", e);
				setReadyState({ ...stateArr[1], message: e });
			};

			ws.current.onclose = (e) => {
				log.showLog("已关闭", e);
				setReadyState({ ...stateArr[3], message: e });
			};
			ws.current.onerror = (e) => {
				log.showLog("有报错", e);
				setReadyState({ ...stateArr[ws.current?.readyState ?? 0], message: e });
			};
			ws.current.onmessage = (e) => {
				log.showLog("有信息", e);
				const message = isJson ? JSON.parse(e.data) : e.data;
				if (message?.type === "ping") {
					const pong = { type: "pong" };
					sendMessage(pong);
				}
				if (message?.type !== "pong") setMessage(message);
			};
		} catch (error) {
			log.showLog("有报错", error);
		}
	};

	const webSocketInit = (url: string) => {
		try {
			log.showLog("触发创建连接", {});
			setStep(1);
			setClose(false);
			if (url !== "" && (!ws.current || ws.current.readyState === 3)) {
				const nowUrl = urlCheck(url);
				creatWebSocket(nowUrl);
				setReadyState({ ...stateArr[0], message: { url: nowUrl } });
				setUrl(nowUrl);
			}
		} catch (error) {
			log.showLog("有报错", error);
		}
	};

	//  关闭 WebSocket
	const closeWebSocket = (restart: boolean = false) => {
		try {
			log.showLog("触发关闭", {});
			if (restart === false) {
				setReadyState({ ...stateArr[2], message: {} });
				setClose(true);
			}
			ws.current?.close();
		} catch (error) {
			log.showLog("有报错", error);
		}
	};

	const reconnect = (restart: boolean = false) => {
		try {
			log.showLog("触发重启", { restart });
			if (restart === true) {
				setStep(step + 1);
			}
			if (readyState.key === 0 || readyState.key === 1) {
				closeWebSocket(restart);
			}
			ws.current = null;
			creatWebSocket(url);
			// 执行完毕后清除定时器
			if (timer) {
				clearTimeout(timer);
				setTimer(null);
			}
		} catch (error) {
			// 执行完毕后清除定时器
			if (timer) {
				clearTimeout(timer);
				setTimer(null);
			}
			log.showLog("有报错", error);
		}
	};

	const restart = () => {
		try {
			if (step >= reloadStep) throw "超过重启次数" + reloadStep;
			if (readyState.key === 3 && isReload === true && close === false) {
				// 定时器，再一定时间后重启
				if (timer) clearTimeout(timer);
				const timeout = setTimeout(() => {
					reconnect(true);
				}, clearTime);
				setTimer(timeout);
			}
		} catch (error) {
			log.showLog("有报错", error);
		}
	};

	// 发送信息
	const sendMessage = (message: unknown) => {
		try {
			log.showLog("当前状态", readyState);
			if (readyState.key !== 1) throw "当前不是连接状态";
			log.showLog("触发发送信息", message);
			const msg = isJson ? JSON.stringify(message) : (message as string);
			ws.current?.send(msg);
		} catch (error) {
			log.showLog("有报错", error);
		}
	};

	useInterval(() => {
		//每隔5秒钟发送一次心跳，避免websocket连接因超时而自动断开
		const ping = { type: "ping" };
		sendMessage(ping);
	}, 5000);

	useEffect(() => {
		log.showLog("readyState信息", readyState);
		restart();
	}, [readyState]);

	useEffect(() => {
		webSocketInit(socketUrl);
	}, []);

	useEffect(() => {
		const handleBeforeUnload = (event: any) => {
			//   event.preventDefault(); // 可选，阻止默认提示消息
			// 执行需要在页面关闭或刷新前进行的操作
			// 可以是发送请求、保存数据、清理资源等
			log.showLog("页面关闭", readyState);
			closeWebSocket();
		};

		window.addEventListener("beforeunload", handleBeforeUnload);

		return () => {
			window.removeEventListener("beforeunload", handleBeforeUnload);
		};
	}, []);

	return {
		wsData,
		readyState,
		closeWebSocket,
		webSocketInit,
		reconnect,
		sendMessage,
		webSocketSelf: ws.current,
	};
};
export default useWebsocket;
